package com.keli.task;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.keli.common.ConfigManager;
import com.keli.common.DateFormatter;
import com.keli.dt.algorithm.RoadInfo;
import com.keli.dt.algorithm.RoadInfoFactory;
import com.keli.dt.analyzer.LaneReportAnalyzer;
import com.keli.dt.analyzer.RoadReportAnalyzer;
import com.keli.dt.dao.ILaneReportDao;
import com.keli.dt.dao.IRoadReportDao;
import com.keli.dt.dao.ITravelReportDao;
import com.keli.dt.model.LaneReport;
import com.keli.dt.model.RoadReport;
import com.keli.dt.model.TravelReport;
import com.keli.util.CustomerContextHolder;
import com.keli.util.DatabaseType;
import com.keli.util.RoadCache;

public class Scheduler extends Thread {
	/** 设置等待时间为1分钟，单位为毫秒 */
	public static long IDLE = 60 * 1000;
	/** 所有数据源类型 */
	public static final DatabaseType[] dbs = {DatabaseType.ZHOUSHAN, DatabaseType.ZHEJIANG};
	private Logger logger = Logger.getLogger(this.getClass());
	/** 开始分析时间，格式为yyyy/MM/dd HH:mm:ss */
	private String startTime;
	private ITravelReportDao travelReportDao;
	private ILaneReportDao laneReportDao;
	private IRoadReportDao roadReportDao;
	private boolean filter = true;	// 过滤速度小于等于0的数据

	public void setStartTime(String startTime) {
		this.startTime = startTime;
	}

	public void setTravelReportDao(ITravelReportDao travelReportDao) {
		this.travelReportDao = travelReportDao;
	}

	public void setLaneReportDao(ILaneReportDao laneReportDao) {
		this.laneReportDao = laneReportDao;
	}

	public void setRoadReportDao(IRoadReportDao roadReportDao) {
		this.roadReportDao = roadReportDao;
	}

	public boolean isFilter() {
		return filter;
	}

	public void setFilter(boolean filter) {
		this.filter = filter;
		logger.info("filter: " + filter);
	}

	/**
	 * 使用文件保存最新分析的时间: <br>
	 * 机器开启时读文件获取开始分析的时间。 <br>
	 * 如果没有读到，则设置开始分析时间为系统当前时间。<br>
	 */
	public Scheduler() {
		String configTime = ConfigManager.loadStartTime();
		if (configTime != null) {
			this.startTime = configTime;
		} else {
			this.startTime = DateFormatter.toString(new Date());
		}
	}

	public Scheduler(String startTime) {
		this.startTime = startTime;
	}

	@Override
	public void run() {
		while (true) {
			// 防止程序处理时间快于系统当前时间，造成无分析数据
			String next = DateFormatter.nextMinute(startTime);
			String now = DateFormatter.toString(new Date());
			if (DateFormatter.max(next, now)) {
				try {
					logger.info("Sleep one minute - startTime: " + startTime
							+ ", currentTime: " + now);
					Thread.sleep(IDLE);
				} catch (InterruptedException e) {
					//e.printStackTrace();
					logger.error("InterruptedException: " + e.getMessage());
				}
			}

			// 数据库操作
			serviceWithAnalyzer();

			ConfigManager.updateStartTime(startTime);
			
			// break; // 用于测试
		}
	}

	/**
	 * 数据库任务操作，使用SQL语句统计分析<br>
	 * 注意：SQL分析功能没有完善且没有测试
	 */
	public void serviceWithSQL() {
		String endTime = DateFormatter.nextMinute(startTime);
		logger.info(String.format("Analyze from %s to %s\n", startTime, endTime));

		List<LaneReport> laneReports = travelReportDao.getLaneReportListByTime(startTime, endTime);

		String now = DateFormatter.toString(new Date());
		insertLaneReport(laneReports, now);

		// 使用SQL语句查询
		List<RoadReport> roadReports = laneReportDao
				.getRoadReportListByReportTime(now);

		insertRoadReport(roadReports, now);

		startTime = endTime;
	}
	
	/**
	 * 获取过车信息
	 * @param endTime 结束时刻
	 * @return
	 */
	private List<TravelReport> getTravelReport(String endTime) {
		CustomerContextHolder.setDatabaseType(DatabaseType.ZHOUSHAN);
		List<TravelReport> travelReports;
		if (filter) {
			travelReports = travelReportDao.getTravelReportListWithFilterByTime(startTime, endTime);
		} else {
			travelReports = travelReportDao.getTravelReportListByTime(startTime, endTime);
		}
		return travelReports;
	}

	/**
	 * 数据库任务操作，使用程序统计分析
	 */
	public void serviceWithAnalyzer() {
		String endTime = DateFormatter.nextMinute(startTime);
		logger.info(String.format("Analyze from %s to %s\n", startTime, endTime));

		List<TravelReport> travelReports = getTravelReport(endTime);
		int travelReportSize = travelReports.size();
		logger.info("travel reports: " + travelReportSize);
		if (travelReportSize == 0) {
			startTime = endTime;
			return;
		}
		// 使用程序统计分析车道信息
		List<LaneReport> laneReports = LaneReportAnalyzer.analyze(travelReports);
		//insertLaneReport(laneReports, now);

		// 使用程序统计分析路段信息
		RoadReportAnalyzer analyzer = new RoadReportAnalyzer(laneReports);
		List<RoadReport> roadReports = analyzer.analyze();
		//insertRoadReport(roadReports, now);
		
		storeReports(laneReports, roadReports);

		startTime = endTime;
	}
	
	private void storeReports(List<LaneReport> laneReports, List<RoadReport> roadReports) {
		String now = DateFormatter.toString(new Date());
		for (DatabaseType type : dbs) {
			// 设置新数据源
			CustomerContextHolder.setDatabaseType(type);
			logger.debug("Set database type: " + type.toString());
			insertLaneReport(laneReports, now);
			// 计算tpi和通行状态
			calcTPIAndStatus(roadReports, type);
			
			insertRoadReport(roadReports, now);
		}
	}
	
	/**
	 * 按照数据源类型计算tpi和status
	 * @param roadReports 路段信息
	 * @param type 数据源类型
	 */
	private void calcTPIAndStatus(List<RoadReport> roadReports, DatabaseType type) {
		RoadInfo info = RoadInfoFactory.getInstance(type);
		int length = roadReports.size();
		for (int i = 0; i < length; i++) {
			RoadReport rr = roadReports.get(i);
			rr.setTPI(null);
			rr.setSTATUS(null);

			Integer roadType = getRoadType(rr.getROAD_ID());
			if (roadType != null) {
				double tpi = info.calcTPI(rr.getSPEED().doubleValue(), roadType.intValue());
				String status = info.getRoadStatus(tpi);
				rr.setTPI(new BigDecimal(tpi));
				rr.setSTATUS(status);
			}
		}
	}
	
	/**
	 * 获取道路等级
	 * @param roadId 路段编号
	 * @return
	 */
	private Integer getRoadType(BigDecimal roadId) {
		Integer roadType = RoadCache.getRoadType(roadId);
		if (roadType == null) {
			roadType = roadReportDao.findType(roadId);
			if (roadType != null) {
				RoadCache.addCache(roadId, roadType);
			}			
		} else {
			logger.debug("Hint the cache with roadId: " + roadId);
		}
		return roadType;
	}

	private void insertLaneReport(List<LaneReport> laneReports, String now) {
		int laneReportSize = laneReports.size();
		logger.info("lane reports: " + laneReportSize);
		if (laneReportSize > 0) {
			//laneReportDao.insert(laneReports, now);
		}
	}

	private void insertRoadReport(List<RoadReport> roadReports, String now) {
		int roadReportsSize = roadReports.size();
		logger.info("road reports: " + roadReportsSize);
		if (roadReportsSize > 0) {
			//roadReportDao.insert(roadReports, now);
		}
	}
}
